#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Git 版本管理模块
纯本地实现，不需要服务器
"""

import os
import subprocess
import json
from pathlib import Path
from typing import List, Dict, Optional, Tuple
from datetime import datetime


class GitVersionManager:
    """Git 版本管理器（纯本地）"""
    
    def __init__(self, dataset_dir: Path):
        """
        初始化版本管理器
        
        Args:
            dataset_dir: 数据集目录路径（paddleocr/dataset）
        """
        self.dataset_dir = Path(dataset_dir).resolve()
        self.annotations_dir = self.dataset_dir / 'annotations'
        self.images_dir = self.dataset_dir / 'images'
        self.git_dir = self.dataset_dir / '.git'
        
    def is_git_initialized(self) -> bool:
        """检查 Git 仓库是否已初始化"""
        return self.git_dir.exists() and self.git_dir.is_dir()
    
    def initialize_git(self) -> Tuple[bool, str]:
        """
        初始化 Git 仓库
        
        Returns:
            (成功标志, 消息)
        """
        if self.is_git_initialized():
            return True, "Git 仓库已存在"
        
        try:
            # 初始化 Git 仓库
            result = subprocess.run(
                ['git', 'init'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode != 0:
                return False, f"Git 初始化失败: {result.stderr}"
            
            # 创建 .gitignore
            gitignore_content = """# 忽略图片文件（只跟踪标注文件）
images/
*.jpg
*.jpeg
*.png
*.bmp
*.gif
*.tif
*.tiff

# 忽略临时文件
*.tmp
*.bak
.DS_Store
__pycache__/
*.pyc
"""
            gitignore_path = self.dataset_dir / '.gitignore'
            with open(gitignore_path, 'w', encoding='utf-8') as f:
                f.write(gitignore_content)
            
            # 首次提交
            subprocess.run(
                ['git', 'add', '.gitignore'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                timeout=10
            )
            
            subprocess.run(
                ['git', 'commit', '-m', 'Initial commit: Add .gitignore'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                timeout=10
            )
            
            return True, "Git 仓库初始化成功"
            
        except subprocess.TimeoutExpired:
            return False, "Git 操作超时"
        except Exception as e:
            return False, f"Git 初始化异常: {str(e)}"
    
    def create_version(self, description: str = "") -> Tuple[bool, str, Optional[str]]:
        """
        创建新版本（提交当前标注状态）
        
        Args:
            description: 版本描述
            
        Returns:
            (成功标志, 消息, 版本ID/commit hash)
        """
        if not self.is_git_initialized():
            success, msg = self.initialize_git()
            if not success:
                return False, msg, None
        
        try:
            # 确保 annotations 目录存在
            self.annotations_dir.mkdir(parents=True, exist_ok=True)
            
            # 检查是否有变更
            result = subprocess.run(
                ['git', 'status', '--porcelain'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if not result.stdout.strip():
                return False, "没有变更需要提交", None
            
            # 添加标注文件
            subprocess.run(
                ['git', 'add', 'annotations/'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                timeout=10
            )
            
            # 创建提交
            commit_message = description if description else f"Update annotations: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
            
            result = subprocess.run(
                ['git', 'commit', '-m', commit_message],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode != 0:
                return False, f"提交失败: {result.stderr}", None
            
            # 获取 commit hash
            result = subprocess.run(
                ['git', 'rev-parse', 'HEAD'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            commit_hash = result.stdout.strip()[:8] if result.returncode == 0 else None
            
            return True, f"版本创建成功: {commit_hash}", commit_hash
            
        except subprocess.TimeoutExpired:
            return False, "Git 操作超时", None
        except Exception as e:
            return False, f"创建版本异常: {str(e)}", None
    
    def list_versions(self, limit: int = 50) -> List[Dict]:
        """
        列出所有版本
        
        Args:
            limit: 最多返回的版本数量
            
        Returns:
            版本列表，每个版本包含：hash, date, message
        """
        if not self.is_git_initialized():
            return []
        
        try:
            result = subprocess.run(
                ['git', 'log', f'--max-count={limit}', '--pretty=format:%H|%ai|%s', '--', 'annotations/'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode != 0:
                return []
            
            versions = []
            for line in result.stdout.strip().split('\n'):
                if not line:
                    continue
                parts = line.split('|', 2)
                if len(parts) >= 3:
                    versions.append({
                        'hash': parts[0][:8],
                        'full_hash': parts[0],
                        'date': parts[1],
                        'message': parts[2]
                    })
                elif len(parts) == 2:
                    versions.append({
                        'hash': parts[0][:8],
                        'full_hash': parts[0],
                        'date': parts[1],
                        'message': ''
                    })
            
            return versions
            
        except subprocess.TimeoutExpired:
            return []
        except Exception as e:
            print(f"列出版本异常: {str(e)}")
            return []
    
    def get_version_info(self, version_hash: str) -> Optional[Dict]:
        """
        获取版本详细信息
        
        Args:
            version_hash: 版本 hash（完整或短 hash）
            
        Returns:
            版本信息字典，包含：hash, date, message, files, stats
        """
        if not self.is_git_initialized():
            return None
        
        try:
            # 获取完整 hash
            result = subprocess.run(
                ['git', 'rev-parse', version_hash],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode != 0:
                return None
            
            full_hash = result.stdout.strip()
            
            # 获取提交信息
            result = subprocess.run(
                ['git', 'show', '--pretty=format:%H|%ai|%an|%ae|%s', '--no-patch', full_hash],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode != 0:
                return None
            
            parts = result.stdout.strip().split('|', 4)
            if len(parts) < 5:
                return None
            
            # 获取文件列表
            result = subprocess.run(
                ['git', 'show', '--name-only', '--pretty=format:', full_hash],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            files = [f.strip() for f in result.stdout.strip().split('\n') if f.strip()] if result.returncode == 0 else []
            
            # 获取统计信息
            result = subprocess.run(
                ['git', 'show', '--stat', '--pretty=format:', full_hash],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            stats = result.stdout.strip() if result.returncode == 0 else ""
            
            return {
                'hash': full_hash[:8],
                'full_hash': full_hash,
                'date': parts[1],
                'author': parts[2],
                'email': parts[3],
                'message': parts[4] if len(parts) > 4 else '',
                'files': files,
                'stats': stats
            }
            
        except subprocess.TimeoutExpired:
            return None
        except Exception as e:
            print(f"获取版本信息异常: {str(e)}")
            return None
    
    def checkout_version(self, version_hash: str) -> Tuple[bool, str]:
        """
        回滚到指定版本
        
        Args:
            version_hash: 版本 hash（完整或短 hash）
            
        Returns:
            (成功标志, 消息)
        """
        if not self.is_git_initialized():
            return False, "Git 仓库未初始化"
        
        try:
            # 获取完整 hash
            result = subprocess.run(
                ['git', 'rev-parse', version_hash],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode != 0:
                return False, f"版本不存在: {version_hash}"
            
            full_hash = result.stdout.strip()
            
            # 检查是否有未提交的变更
            result = subprocess.run(
                ['git', 'status', '--porcelain'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.stdout.strip():
                return False, "存在未提交的变更，请先提交或丢弃变更"
            
            # 检出指定版本的标注文件
            result = subprocess.run(
                ['git', 'checkout', full_hash, '--', 'annotations/'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode != 0:
                return False, f"回滚失败: {result.stderr}"
            
            return True, f"已回滚到版本: {full_hash[:8]}"
            
        except subprocess.TimeoutExpired:
            return False, "Git 操作超时"
        except Exception as e:
            return False, f"回滚异常: {str(e)}"
    
    def delete_version(self, version_hash: str) -> Tuple[bool, str]:
        """
        删除指定版本（谨慎使用）
        
        Args:
            version_hash: 版本 hash（完整或短 hash）
            
        Returns:
            (成功标志, 消息)
        """
        if not self.is_git_initialized():
            return False, "Git 仓库未初始化"
        
        try:
            # 获取完整 hash
            result = subprocess.run(
                ['git', 'rev-parse', version_hash],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode != 0:
                return False, f"版本不存在: {version_hash}"
            
            full_hash = result.stdout.strip()
            
            # 检查是否是 HEAD
            result = subprocess.run(
                ['git', 'rev-parse', 'HEAD'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode == 0 and result.stdout.strip() == full_hash:
                return False, "不能删除当前版本（HEAD）"
            
            # 使用 git reset 或 git rebase 删除（这里使用交互式 rebase）
            # 注意：这是一个危险操作，需要用户确认
            return False, "删除版本功能需要手动使用 git rebase 或 git reset，请谨慎操作"
            
        except subprocess.TimeoutExpired:
            return False, "Git 操作超时"
        except Exception as e:
            return False, f"删除版本异常: {str(e)}"
    
    def get_current_version(self) -> Optional[str]:
        """
        获取当前版本 hash
        
        Returns:
            当前版本的 hash（短格式）
        """
        if not self.is_git_initialized():
            return None
        
        try:
            result = subprocess.run(
                ['git', 'rev-parse', '--short', 'HEAD'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode == 0:
                return result.stdout.strip()
            return None
            
        except subprocess.TimeoutExpired:
            return None
        except Exception as e:
            print(f"获取当前版本异常: {str(e)}")
            return None
    
    def get_diff(self, version_hash1: Optional[str] = None, version_hash2: Optional[str] = None) -> Optional[str]:
        """
        获取两个版本之间的差异
        
        Args:
            version_hash1: 版本1 hash（None 表示当前版本）
            version_hash2: 版本2 hash（None 表示当前版本）
            
        Returns:
            差异文本
        """
        if not self.is_git_initialized():
            return None
        
        try:
            if version_hash1 is None:
                version_hash1 = 'HEAD'
            if version_hash2 is None:
                version_hash2 = 'HEAD'
            
            result = subprocess.run(
                ['git', 'diff', version_hash1, version_hash2, '--', 'annotations/'],
                cwd=str(self.dataset_dir),
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode == 0:
                return result.stdout
            return None
            
        except subprocess.TimeoutExpired:
            return None
        except Exception as e:
            print(f"获取差异异常: {str(e)}")
            return None

